#include"aesencode.h"
uint32_t now_key[4] = {0,0,0,0};
/********************************
* func: write data to address
*   param:
*       uint32_t @addr -> address
*       uint32_t @data -> data
*   return 
*       nop   -> nop
*********************************/

void write_reg(uint32_t addr,uint32_t data){
#ifndef SIM
    *((volatile uint32_t*) addr) = data;
    printf("[DEBUG]-> [WRITE] addr: %08x data: %08x\r\n",addr,data);
#else
    dut_ptr->AHB_HCLK   = 1;
    dut_ptr->AHB_HADDR  = addr;
    dut_ptr->AHB_HSEL   = 1;
    dut_ptr->AHB_HWRITE = 1;
    dut_ptr->AHB_HTRANS = 2;

    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif

    dut_ptr->AHB_HCLK = 0;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif
#ifdef WR_DEBUG
    printf("[time:%5d] --> write addr is %08x\r\n", mytime / 2, addr);
#endif
    dut_ptr->AHB_HCLK = 1;
    dut_ptr->AHB_HWDATA = data;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif

    dut_ptr->AHB_HCLK = 0;
    dut_ptr->AHB_HSEL = 0;
    dut_ptr->AHB_HWRITE = 0;
    dut_ptr->AHB_HTRANS = 0;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif
#ifdef WR_DEBUG
    printf("[time:%5d] --> write data is %08x\r\n", mytime / 2, data);
#endif
#endif
}

/********************************
* func:read data from address
*   param:
*       uint32_t @addr -> address
*   return 
*       uint32_t -> read data
*********************************/
uint32_t read_reg(uint32_t addr){
    uint32_t t;
#ifndef SIM
    t = *((volatile uint32_t*) addr);
    printf("[DEBUG]-> [READ ] addr: %08x data: %08x\r\n",addr,t);
    return t;
#else
    dut_ptr->AHB_HCLK = 1;
    dut_ptr->AHB_HADDR = addr;
    dut_ptr->AHB_HSEL = 1;
    dut_ptr->AHB_HTRANS = 2;
    dut_ptr->AHB_HWRITE = 0;

    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif

    dut_ptr->AHB_HCLK = 0;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif
#ifdef WR_DEBUG
    printf("[time:%5d] --> read  addr is %08x\r\n", mytime / 2, addr);
#endif
    dut_ptr->AHB_HCLK = 1;
    t = dut_ptr->AHB_HRDATA;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif
    dut_ptr->AHB_HCLK = 0;
    dut_ptr->AHB_HSEL = 0;
    dut_ptr->AHB_HWRITE = 0;
    dut_ptr->AHB_HTRANS = 0;
    dut_ptr->eval();

#ifdef VM_TRACE
    fp->dump(mytime);
    mytime++;
#endif
#ifdef WR_DEBUG
    printf("[time:%5d] --> read  data is %08x\r\n", mytime / 2, t);
#endif
    return t;
#endif
}

#ifdef SIM
/*********************
* func: delay and dump wave 1 cycle
*   param:
*       int num -> cycle number 
*   return:
*       nop
**********************/
void delay_cycle(int num)
{
    for (int i = 0; i < num; i++)
    {
        dut_ptr->AHB_HCLK = 1;
        dut_ptr->eval();

#ifdef VM_TRACE
        fp->dump(mytime);
        mytime++;
#endif

        dut_ptr->AHB_HCLK = 0;
        dut_ptr->eval();

#ifdef VM_TRACE
        fp->dump(mytime);
        mytime++;
#endif

#ifdef WR_DEBUG
        printf("[time:%5d] --> delay  1 cycle\r\n", mytime / 2);
#endif
    }
}
#endif

/********************************
* func:print 128bit 16 data to screen
*   param:
*       uint32_t* @p -> 128bit array uint32_t p[AES_SPLITE]
*   return:
*       nop
*********************************/
void print128(uint32_t* p){
    for(int i=0;i<AES_SPLITE;i++){
        printf("%08x",p[i]);
    }
}

/*******************************
* func:control finish key exp
*   param:  
*       uint32_t * @key -> key
*   return:
*       nop
********************************/
void aes_128_keyexp(uint32_t* key){
    /* load key */
    for (int i=0;i<AES_SPLITE;i++){
        write_reg(AHB_SLAVE_BASE + AES_DATA + i *4,key[i]);
    }

    /* start keyexp */
    write_reg(AHB_SLAVE_BASE + AES_CTRL, AES_CMD_KEYEXP);

#ifdef SIM
    delay_cycle(2);
#endif

    /* wait for caculate done */
    while(!(read_reg(AHB_SLAVE_BASE + AES_CTRL) & AES_STA_KEYEXP));
#ifdef TRANS_DEBUG
    printf("[TRANS]: keyexp\r\n");
#endif
}

/*****************************
* func: aes encode
*   param:
*       uint32_t * @data -> txt
*   return:
*       uint32_t * @out -> caculate end
******************************/
void aes_128_encode(uint32_t* data , uint32_t* out){
    #ifndef SIM
	printf("[DEBUG]-> encode start\r\n");
    #endif
    /* load txt*/
    for(int i=0;i<AES_SPLITE;i++){
        write_reg(AHB_SLAVE_BASE + AES_DATA + i*4,data[i]);
    }

    /* start encode */
    write_reg(AHB_SLAVE_BASE + AES_CTRL,AES_CMD_ENCODE);

#ifdef SIM
    delay_cycle(2);
#endif

    /* wait for caculate done */
    while(!(read_reg(AHB_SLAVE_BASE + AES_CTRL) & AES_STA_ENCODE));


    /* read aes caculate out */
    for(int i=0;i<AES_SPLITE;i++){
        out[i] = read_reg(AHB_SLAVE_BASE + AES_OUT + i*4);
    }
#ifdef TRANS_DEBUG
printf("[TRANS]: encode\r\n");
#endif
}

/*****************************
* func:aes 128 caculate ,if key not build ,it can skip
*   param:
*      uint32_t* data -> txt
*      uint32_t* key  -> key
*      uint32_t* out  -> out
*   reutrn:
*       nop
*****************************/
void aes_128_caculate(uint32_t* data,uint32_t* key,uint32_t* out){
    if(0 != memcmp(key,now_key,AES_SPLITE)){
    	#ifndef SIM
        printf("[DEBUG]-> key mismatch ,now is rebuid\r\n");
        #endif
        aes_128_keyexp(key);
        /* update key */
        memcpy(now_key,key,AES_SPLITE);
    }
    aes_128_encode(data,out);
}
